package com.open.exam.service;

import com.open.exam.common.*;
import com.open.exam.databasemodel.*;
import com.open.exam.dto.*;
import com.open.exam.enums.*;
import com.open.exam.itemmodel.ICreaterFactory;
import com.open.exam.mapper.*;
import com.open.exam.utils.*;
import com.openexam.openqti.openqtipaperquestion.*;
import com.openexam.openqti.qti.AssessmentItem;
import com.openexam.openqti.qti.AssessmentTest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import java.io.File;
import java.util.*;

/**
 * @author 奶茶
 * Created on 2017/11/14.
 */
@Service("examPaperService")
@Transactional(rollbackFor = Exception.class)
public class ExamPaperService {

    private static final Logger logger = LoggerFactory.getLogger(ExamPaperService.class);

    @Autowired
    private ExamineeArrangeMapper examineeArrangeMapper;
    @Autowired
    private ExamSubjectMapper examSubjectMapper;
    @Autowired
    private ExamScenesMapper examScenesMapper;
    @Autowired
    private ExamPaperMapper examPaperMapper;
    @Autowired
    private ExamPaperItemMapper examPaperItemMapper;

    private static JAXBContext assessmentTestJAXBContext;
    private static JAXBContext assessmentItemJAXBContext;
    static {
        try {
            assessmentTestJAXBContext = JAXBContext.newInstance(AssessmentTest.class);
            assessmentItemJAXBContext = JAXBContext.newInstance(AssessmentItem.class);
        } catch (JAXBException e) {
            logger.error("JAXBException",e);
        }
    }

    private static final String FORMATPATH = "%s/%s/%s/%s/";
    private static final String PAPERFOLDER = "/files/papers";

    /**
     * 生成试卷前判断
     * @param planId
     * @param subjectId
     * @param adminInfo
     * @return
     */
    public OperationResult paperGenerat(String planId, String subjectId, AdminInfo adminInfo) throws Exception {
        OperationResult result = isSeatSet(planId, adminInfo.getAppID());
        if(result.getResultType() != OperationResultType.Success){
            return new OperationResult(OperationResultType.Error,"当前座位号没设置完全，需要设置");
        }

        Integer counts = paperGenerats(planId, subjectId, adminInfo);
        return new OperationResult(OperationResultType.Success,counts);
    }

    /**
     * 当前计划的座位号是否需要限制，以及是否已生成座位号
     * @param planId
     * @param appId
     * @return
     */
    public OperationResult isSeatSet(String planId, String appId){
        List<ExamPlanInfo> examPlanInfos = examineeArrangeMapper.findExamPlanInfoBySomeWhere(planId, appId);
        if(!examPlanInfos.isEmpty()){
            return new OperationResult(OperationResultType.Success);
        }
        List<ArrangesInfo> arrangesInfos = examineeArrangeMapper.ExamineeArrangesWhere(planId, appId);
        List<ExamComputer> examComputers = examineeArrangeMapper.findExamComputerBySomeWhere(appId, planId);

        return arrangesInfos.size() <= examComputers.size()
                ? new OperationResult(OperationResultType.Success)
                : new OperationResult(OperationResultType.Warning,"当前座位号没设置完全，需要设置！");
    }

    /**
     * 生成试卷
     * @param planId 考试计划ID
     * @param subjectId 科目ID
     * @param adminInfo 主办方
     * @return
     */
    public Integer paperGenerats(String planId, String subjectId, AdminInfo adminInfo) {
        Integer paperCount = 0;
        String appId = adminInfo.getAppID();
        //获取当前科目的所有试卷
        List<ExamPaper> examPapers = examPaperMapper.getExamPapersBySomeWhere(appId, planId, subjectId);
        examPapers.forEach(examPaper -> {
            int itemCount = 0;
            double score = 0.0;
            int i = 0;
            List<ExamPaperItem> examPaperItems = examPaperItemInfo(examPaper.getExamPaperID());
            List<ExamineeExamPaperItem> paperItemList = new ArrayList<>();
            for (ExamPaperItem examPaperItem:examPaperItems) {
                ExamineeExamPaperItem paperItem = new ExamineeExamPaperItem();
                paperItem.setItemID(examPaperItem.getItemID());
                paperItem.setItemContent(examPaperItem.getItemContent());
                paperItemList.add(paperItem);
            }

            TestPaperOutModel testPaperOutModel = new TestPaperOutModel();
            testPaperOutModel.setTestString(examPaper.getExamPaperContent());
            TestPaperOutModel outModel = new TestPaperFromPackageGenerator().generator(testPaperOutModel, false,assessmentTestJAXBContext,assessmentItemJAXBContext);

            TestPaperTemplate testPaper = new TestPaperTemplate();
            OpenAssessmentTest openAssessmentTest = new OpenAssessmentTest();
            try {
                openAssessmentTest.LoadFromString(outModel.getTestString(),assessmentTestJAXBContext);
                for (OpenTestPart testPart:openAssessmentTest.getTestPartCollection()) {
                    for (OpenAssessmentSection section:testPart.getAssessmentSectionCollection()) {
                        score += section.getScore();
                        itemCount += section.getItemCount();

                        SectionTemplate sectionTemplate = new SectionTemplate();
                        sectionTemplate.setScore(section.getScore());
                        sectionTemplate.setIdentifier(section.getIdentifier());
                        sectionTemplate.setItemCount(section.getItemCount());
                        sectionTemplate.setTitle(section.getTitle());
                        sectionTemplate.setItemIndex(testPaper.getSectionTemplateCollection().size() + 1);

                        for (OpenAssessmentItemRef itemRef:section.getAssessmentItemRefCollection()) {
                            OpenAssessmentItem item = OpenAssessmentItem.createInstance(itemRef.getType());
                            item.LoadFromString(CommonFunction.getExamPaperItemById(paperItemList,itemRef.getIdentifier()).getItemContent(),assessmentItemJAXBContext);

                            ItemTemplate temp = ICreaterFactory.getItemObject(item);
                            temp.setAssessmentItemType(itemRef.getType().getIndex());
                            temp.setIdentifier(itemRef.getIdentifier());
                            temp.setExample(itemRef.isExample());
                            temp.setMedia(itemRef.getMedia());
                            temp.setSubjective(itemRef.isSubjective());
                            temp.setTitle(item.getTitle());
                            temp.setWeight(itemRef.getWeight());
                            temp.setResponseDuration(itemRef.getResponseDuration());
                            temp.setQuestionAnalysis("");
                            temp.setPromptShowDuration(itemRef.getPromptShowDuration());
                            temp.setScore(itemRef.getWeight());
                            temp.setItemIndex(sectionTemplate.getItemTemplateCollection().size()+1);
                            temp.setSequenceIndex(++i);
                            sectionTemplate.getItemTemplateCollection().add(temp);
                        }
                        testPaper.getSectionTemplateCollection().add(sectionTemplate);
                    }
                }
                testPaper.setIdentifier(examPaper.getExamPaperID());
                testPaper.setTitle(openAssessmentTest.getTitle());
                testPaper.setItemCount(itemCount);
                testPaper.setScore(score);

                examPaper.setExamPaperContentJson(GsonUtil.toJson(testPaper));
                examPaperMapper.updateExamPaper(examPaper);
                //获取缓存试卷key
                String paperKey = CacheKey.getPaperKey(planId, subjectId, examPaper.getExamPaperID());
                //获取缓存时长
                String expireTime = RedisUtil.getValue(planId);
                if(!StringUtils.isEmpty(expireTime)){
                    RedisUtil.setValue(paperKey,examPaper.getExamPaperContentJson(),Integer.valueOf(expireTime));
                }else{
                    //计算计划的周期时长  场次结束时间和当前时间的差值 作为考生试卷的缓存的过期时间
                    ExamScenes examScene = examScenesMapper.getExamSceneByExamPlanID(planId);
                    String endTime = examScene.getPlanEndTime();
                    Long time = (DateUtil.convertStringToDate(endTime).getTime() - System.currentTimeMillis())/1000;
                    RedisUtil.setValue(planId,time.toString(),time.intValue());
                    RedisUtil.setValue(paperKey,examPaper.getExamPaperContentJson(),time.intValue());
                }
            } catch (Exception e) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                e.printStackTrace();
            }
        });

        //获取未生成试卷的考生编排信息
        List<ExamineeArrange> examineeArranges = examineeArrangeInfo(planId, subjectId, appId);
        examineeArranges.forEach(examineeArrange -> {
            examineeArrange.setExamPaperID(examPapers.get(new Random().nextInt(examPapers.size())).getExamPaperID());
            examineeArrangeMapper.updateExamineeArrange(examineeArrange);
        });
        return paperCount;
    }

    /**
     * 获取未生成试卷的考生编排信息
     * @param planId
     * @param subjectId
     * @param appId
     * @return
     */
    public List<ExamineeArrange> examineeArrangeInfo(String planId, String subjectId, String appId){
        return examineeArrangeMapper.examineeArrangeWhere(appId, planId, subjectId);
    }

    /**
     * 根据考试计划，科目获取课程原始试卷信息
     * @param planId
     * @param subjectId
     * @param appId
     * @return
     */
    public ExamPaper examPaperInfo(String planId, String subjectId, String appId){
        List<ExamPaper> examPapers = examPaperMapper.getExamPapersBySomeWhere(appId, planId, subjectId);
        int count = new Random().nextInt(examPapers.size());
        return examPapers.get(count);
    }

    /**
     * 根据试卷获取科目原始试题信息
     * @param paperId
     * @return
     */
    public List<ExamPaperItem> examPaperItemInfo(String paperId){
        return examPaperMapper.findExamPaperItemsByPaperId(paperId);
    }

    ///**
    // * 生成Json试卷
    // * @param examPaper
    // * @param examPaperItems
    // */
    //public void buildJsonPaper(ExamineeExamPaper examPaper,List<ExamineeExamPaperItem> examPaperItems,Integer deploymentMode) throws Exception {
    //    TestPaperTemplate testPaper = new TestPaperTemplate();
    //    OpenAssessmentTest openAssessmentTest = new OpenAssessmentTest();
    //    openAssessmentTest.LoadFromString(examPaper.getExamPaperContent(),assessmentTestJAXBContext);
    //
    //    Integer itemCount = 0;
    //    Double score = 0.0;
    //    Integer i = 0;
    //
    //    for (OpenTestPart testPart:openAssessmentTest.getTestPartCollection()) {
    //        for (OpenAssessmentSection section:testPart.getAssessmentSectionCollection()) {
    //            score += section.getScore();
    //            itemCount += section.getItemCount();
    //
    //            SectionTemplate sectionTemplate = new SectionTemplate();
    //            sectionTemplate.setScore(section.getScore());
    //            sectionTemplate.setIdentifier(section.getIdentifier());
    //            sectionTemplate.setItemCount(section.getItemCount());
    //            sectionTemplate.setTitle(section.getTitle());
    //            sectionTemplate.setItemIndex(testPaper.getSectionTemplateCollection().size() + 1);
    //
    //            for (OpenAssessmentItemRef itemRef:section.getAssessmentItemRefCollection()) {
    //                OpenAssessmentItem item = OpenAssessmentItem.createInstance(itemRef.getType());
    //                item.LoadFromString(CommonFunction.getExamPaperItemById(examPaperItems,itemRef.getIdentifier()).getItemContent(),assessmentItemJAXBContext);
    //
    //                ItemTemplate temp = ICreaterFactory.getItemObject(item);
    //                temp.setAssessmentItemType(itemRef.getType().getIndex());
    //                temp.setIdentifier(itemRef.getIdentifier());
    //                temp.setExample(itemRef.isExample());
    //                temp.setMedia(itemRef.getMedia());
    //                temp.setSubjective(itemRef.isSubjective());
    //                temp.setTitle(item.getTitle());
    //                temp.setWeight(itemRef.getWeight());
    //                temp.setResponseDuration(itemRef.getResponseDuration());
    //                temp.setQuestionAnalysis("");
    //                temp.setPromptShowDuration(itemRef.getPromptShowDuration());
    //                temp.setScore(itemRef.getWeight());
    //                temp.setItemIndex(sectionTemplate.getItemTemplateCollection().size()+1);
    //                temp.setSequenceIndex(++i);
    //                sectionTemplate.getItemTemplateCollection().add(temp);
    //            }
    //            testPaper.getSectionTemplateCollection().add(sectionTemplate);
    //        }
    //    }
    //
    //    testPaper.setIdentifier(examPaper.getExamPaperInfoID());
    //    testPaper.setTitle(openAssessmentTest.getTitle());
    //    testPaper.setItemCount(itemCount);
    //    testPaper.setScore(score);
    //
    //    String paperStr = GsonUtil.toJson(testPaper);
    //    examPaper.setExamPaperContent(paperStr);
    //
    //    if(deploymentMode.equals(DeploymentMode.LAN_Deployment.getPrefix())){
    //        String path = String.format(FORMATPATH, ExamSitePath.rootPath + PAPERFOLDER,examPaper.getAppID(),examPaper.getExamPlanInfoID(),examPaper.getExamSubjectID());
    //        String filePath = String.format("%s.json",examPaper.getExamPaperInfoID());
    //
    //        FileUtil.writeStrToFile(path,filePath,paperStr);
    //    }else {
    //        //将试卷放入缓存
    //        String examinerCacheKey = CacheKey.getExaminerPaperKey(examPaper.getExamPlanInfoID(),examPaper.getExamSubjectID(),examPaper.getExamSceneID(),examPaper.getExamineeID());
    //        //从缓存中获取计划的周期时长
    //        String examPlanID = examPaper.getExamPlanInfoID();
    //        String examPlanTime = RedisUtil.getValue(examPlanID);
    //        if(!StringUtils.isEmpty(examPlanTime)){
    //            RedisUtil.setValue(examinerCacheKey,paperStr,Integer.valueOf(examPlanTime));
    //        }else{
    //            //计算计划的周期时长  场次结束时间和当前时间的差值 作为考生试卷的缓存的过期时间
    //            ExamScenes examScene = examScenesMapper.getExamSceneByExamPlanID(examPlanID);
    //            String endTime = examScene.getPlanEndTime();
    //            Long time = (DateUtil.convertStringToDate(endTime).getTime() - System.currentTimeMillis())/1000;
    //            RedisUtil.setValue(examPaper.getExamPlanInfoID(),time.toString(),time.intValue());
    //            RedisUtil.setValue(examinerCacheKey,paperStr,time.intValue());
    //        }
    //    }
    //    saveExamineeExam(examPaper);
    //}
    //
    //public OperationResult generateExaminerPaperToRedis(String examPlanID){
    //    String examPaperToRedis = examineeExamPaperMapper.findExamPaperToRedis(examPlanID);
    //    List<ExamineeExamPaper> examineeExamPapers = examineeExamPaperMapper.findExamineeExamPaperByPlanId(examPlanID);
    //
    //    for (ExamineeExamPaper examPaper : examineeExamPapers) {
    //        String examinerCacheKey = CacheKey.getExaminerPaperKey(examPlanID,examPaper.getExamSubjectID(),examPaper.getExamSceneID(),examPaper.getExamineeID());
    //        RedisUtil.setValue(examinerCacheKey,examPaperToRedis,600000);
    //    }
    //
    //    return new OperationResult(OperationResultType.Success);
    //}

    /**
     * 保存考生试卷和试题
     * @param paper
     * @return
     */
    //public void saveExamineeExam(ExamineeExamPaper paper){
    //    // 基础参数检查
    //    examineeExamPaperMapper.insertExamineeExamPaper(paper);
    //}


    /**
     * 判断当前计划下试卷是否生成完成
     * @param planId
     * @return
     */
    public Boolean state(String planId){
        return examSubjectMapper.findFailDownloadSubjectInfo(planId).size() == 0;
    }

    int i = 2;
    /**
     * 下载科目试卷
     * @param adminInfo
     * @param examSubject
     * @param prefixPath
     * @param deploymentMode
     * @param examPlanID
     * @return
     */
    public void downLoadExamSubjectPaper(AdminInfo adminInfo, ExamSubject examSubject, StringBuilder prefixPath, Integer deploymentMode, String examPlanID){
        try {
            //int x = 1/i--;
            LoadXml loadXml = new LoadXml();
            List<ExamPaper> examPaperList = new ArrayList<>();
            List<ExamPaperItem> examPaperItemList = new ArrayList<>();
            String basePath = prefixPath.toString();
            //获取该科目的试卷存放路径
            String filePath = basePath + examSubject.getSubjectCode();

            File file = new File(filePath);
            if(file.exists() && file.isDirectory()){
                for (File paperFile:file.listFiles()) {
                    if(paperFile.isFile()){
                        String paperFilePath = paperFile.getAbsolutePath();
                        String paperID = paperFile.getName().split(".xml")[0];
                        String examPaperID = UUID.randomUUID().toString();
                        String paperContent = FileUtil.getFileContent(paperFilePath);
                        ExamPaper examPaper = new ExamPaper();
                        examPaper.setAppID(adminInfo.getAppID());
                        examPaper.setPaperID(paperID);
                        examPaper.setExamPlanInfoID(examPlanID);
                        examPaper.setExamSubjectID(examSubject.getExamSubjectID());
                        examPaper.setExamPaperContent(paperContent);
                        examPaper.setExamPaperContentJson("");
                        examPaper.setPaperVersion(1);
                        examPaper.setExamPaperID(examPaperID);
                        examPaperList.add(examPaper);

                        OpenAssessmentTest openAssessmentTest = loadXml.loadExamPaperXml(paperFilePath,assessmentTestJAXBContext);
                        List<OpenAssessmentItem> questionList = loadXml.getQuestionList(openAssessmentTest,filePath,assessmentItemJAXBContext);

                        for (OpenAssessmentItem openAssessmentItem:questionList) {
                            String xmlString = openAssessmentItem.getXmlString(assessmentItemJAXBContext);
                            //直接映射 不需要复制图片
                            ExamPaperItem examPaperItem = new ExamPaperItem();
                            examPaperItem.setPaperID(examPaperID);
                            examPaperItem.setItemContent(xmlString);
                            examPaperItem.setItemID(openAssessmentItem.getIdentifier());
                            examPaperItemList.add(examPaperItem);
                        }
                    }
                }
            }
            //机考模式 删除下载的压缩文件 待下载逻辑实现
            if(deploymentMode.equals(DeploymentMode.LAN_Deployment.getPrefix())){
                FileUtil.deleteFile("");
            }

            //插入当前科目试卷和试题
            insertExamPaper(examPaperList);
            insertExamPaperItemList(examPaperItemList);

            //生成当前科目下所有考生试卷
            OperationResult paperGenerateResult = paperGenerat(examPlanID, examSubject.getExamSubjectID(), adminInfo);
            if(paperGenerateResult.getResultType().equals(OperationResultType.Success)){
                //下载完成将该科目试卷状态修改为_2(DownloadCompleteAndPaperGenerate)
                examSubject.setSubjectPaperStatus(SubjectPaperStatus.DownloadCompleteAndPaperGenerate.getPrefix().shortValue());
            }
        }catch (Exception e){
            examSubject.setSubjectPaperStatus(SubjectPaperStatus.DownloadFail.getPrefix().shortValue());
            logger.error("科目试卷下载异常！examSubjectID:" + examSubject.getExamSubjectID(),e);
        }finally {
            examSubjectMapper.updateExamSubjectPaperStatus(examSubject);
        }
    }

    private void insertExamPaper(List<ExamPaper> examPaperList){
        //添加或修改ExamPaper
        for (ExamPaper examPaper:examPaperList) {
            examPaperMapper.insertExamPaperIFNotExist(examPaper);
        }
    }

    private void insertExamPaperItemList(List<ExamPaperItem> examPaperItemList){
        //添加ExamPaperItem
        for (ExamPaperItem examPaperItem:examPaperItemList) {
            examPaperItemMapper.insertExamPaperItemIFNotExist(examPaperItem);
        }
    }
}
